
from Tkinter import *
from controller import Controller
import ImageTk
import Tkinter
import util
import tkFileDialog
import Image

def create_frame(root, border_width):
  '''Creates a frame rooted at root with embossed border with specified width using grid system
  
  Returns it'''
  base_frame = Frame(root, borderwidth=border_width, relief=SUNKEN)
  base_frame.grid(column=0, row=0, sticky=(N, W, E, S))
  base_frame.rowconfigure(0, weight=1)
  base_frame.columnconfigure(0, weight=1)
  base_frame.pack()
  return base_frame

def create_file_chooser(root, text, save_as=False):
  '''Creates a small collection of widget that can select a file an open it.
  
  Returns the string variable used to store the filename. By default it is None'''
  var = StringVar()
  var.set('None')
  Label(root, text=text).grid(row=0, column=0)
  
  def on_click():
    if not save_as:
      filename = tkFileDialog.askopenfilename()
    else:
      filename = tkFileDialog.asksaveasfilename()
    if filename:
      var.set(filename)
    else:
      var.set('None')
  
  Button(root, text='Browse...', command=on_click).grid(row=0, column=1)
  
  Label(root, textvariable=var).grid(row=1, column=0)
  return var

class SetParameterIndexingWindow:
  def __init__(self, master):
    self.master = master
    self.master.title('Impulse Engine MK 1.7 -- Tactical Briefing')
      
    base = create_frame(master, 0)
    
    logo = Image.open('resource/logo.jpeg')
    self.logo = ImageTk.PhotoImage(logo)
    Label(base, image=self.logo).grid(row=0, column=0)
    Label(base, text='Set Indexing Parameters').grid(row=1, column=0)
    #Label(base, height=separator_height, width=separator_width, bg='Blue').grid(row=2, column=0)
    stopword = create_frame(base, 4)
    stopword.grid(row=2, column=0)

    inverted_index = create_frame(base, 4)
    inverted_index.grid(row=6, column=0)
    
    doc_collection = create_frame(base, 4)
    doc_collection.grid(row=3, column=0)
    
    query = create_frame(base, 4)
    query.grid(row=4, column=0)
    
    relevance_judgment = create_frame(base, 4)
    relevance_judgment.grid(row=5, column=0)
    
    upper2 = create_frame(base, 4)
    upper2.grid(row=7, column=0)
    Label(base, text='Word Weighting').grid(row=8, column=0)
    lower = create_frame(base, 0)
    lower.grid(row=9, column=0)
    left = create_frame(lower, 4)
    left.grid(row=1, column=0)
    right = create_frame(lower, 4)
    right.grid(row=1, column=1)
    
    Button(base, text='Commence War', command=self.explode_button_clicked).grid(row=10, column=0)

    self.stopword_removal_data = create_file_chooser(stopword, 'Stopword Removal Data:')
    self.inverted_index = create_file_chooser(inverted_index, 'Save Inverted Index as:', save_as=True)
    self.doc_collection = create_file_chooser(doc_collection, 'Document Collection:')
    self.query = create_file_chooser(query, 'Query:')
    self.relevance_judgment = create_file_chooser(relevance_judgment, 'Relevance Judgment:')

    self.use_stemming = IntVar()
    Checkbutton(upper2, text="Use Stemming", variable=self.use_stemming).grid(row=5, column=0)
    
    Label(left, text='DOC').grid(row=1, column=0)
    Label(right, text='QUERY').grid(row=1, column=0)
    
    tf_kiri = create_frame(left, 4)
    tf_kiri.grid(row=2, column=0)
    tf_kanan = create_frame(right, 4)
    tf_kanan.grid(row=2, column=0)
    
    self.doc_tf_type = StringVar()
    self.query_tf_type = StringVar()
    first_button = Radiobutton(tf_kiri, text="Binary TF", variable=self.doc_tf_type, value='binary')
    first_button.grid(row=1, column=0)
    first_button.select()
    
    first_button = Radiobutton(tf_kanan, text="Binary TF", variable=self.query_tf_type, value='binary')
    first_button.grid(row=1, column=0)
    first_button.select()
    
    Radiobutton(tf_kiri, text='Logarithmic TF', variable=self.doc_tf_type, value='log').grid(row=2, column=0)
    Radiobutton(tf_kanan, text='Logarithmic TF', variable=self.query_tf_type, value='log').grid(row=2, column=0)

    Radiobutton(tf_kiri, text='Augmented TF', variable=self.doc_tf_type, value='augmented').grid(row=3, column=0)
    Radiobutton(tf_kanan, text='Augmented TF', variable=self.query_tf_type, value='augmented').grid(row=3, column=0)

    Radiobutton(tf_kiri, text='Raw TF', variable=self.doc_tf_type, value='raw').grid(row=4, column=0)
    Radiobutton(tf_kanan, text='Raw TF', variable=self.query_tf_type, value='raw').grid(row=4, column=0)

    self.doc_use_idf = IntVar()
    self.query_use_idf = IntVar()
    
    self.doc_use_normalization = IntVar()
    self.query_use_normalization = IntVar()
    
    Checkbutton(left, text='Use IDF', var=self.doc_use_idf).grid(row=3, column=0)
    Checkbutton(right, text='Use IDF', var=self.query_use_idf).grid(row=3, column=0)

    Checkbutton(left, text='Use Normalization', var=self.doc_use_normalization).grid(row=4, column=0)
    Checkbutton(right, text='Use Normalization', var=self.query_use_normalization).grid(row=4, column=0)

  def explode_button_clicked(self):
    # TODO(irvan)
    stop = self.stopword_removal_data.get()
    inv = self.inverted_index.get()
    doc_col = self.doc_collection.get()
    query = self.query.get()
    rel_judg = self.relevance_judgment.get()
    
    def Normalize(val):
      if val == 'None':
        return None
      else:
        return val
    
    (stop, inv, doc_col, query, rel_judg) = map(Normalize, [stop, inv, doc_col, query, rel_judg])
    
    controller = Controller(
      stop,
      inv,
      doc_col,
      query,
      rel_judg,
      self.use_stemming.get(),
      self.doc_tf_type.get(),
      self.query_tf_type.get(),
      self.doc_use_idf.get(),
      self.query_use_idf.get(),
      self.doc_use_normalization.get(),
      self.query_use_normalization.get())
    
    root = Tkinter.Toplevel()
    result = ResultWindow(root, engine=controller)  # Placeholder so it won't be garbage collected
    root.mainloop()

class ResultWindow:
  def __init__(self, master, engine):
    self.master = master
    self.master.title('Impulse Engine MK 1.7 -- Battle Aftermath')
    
    self.engine = engine
      
    base = create_frame(master, 0)
    
    logo = Image.open('resource/evil.jpg')
    self.logo = ImageTk.PhotoImage(logo)
    Label(base, image=self.logo, height=80).grid(row=0, column=0)
    
    experimental = create_frame(base, 4)
    experimental.grid(row=1, column=0)
    
    interactive = create_frame(base, 4)
    interactive.grid(row=2, column=0)
    
    Label(experimental, text='Experimental Results').grid(row=0, column=0)
    Button(experimental, text='Save Retrieval Result',
           command=self.save_retrieval_result_button_clicked).grid(row=1, column=0)
    Button(experimental, text='Save Performance',
           command=self.save_performance_button_clicked).grid(row=2, column=0)
    
    Label(interactive, text='Interactive Results').grid(row=0, column=0)
    Label(interactive, text='Query:').grid(row=1, column=0)
    self.query = StringVar()
    self.query.set('Impulse');

    Entry(interactive, width=75, textvariable=self.query).grid(
      row=2, column=0, sticky=(W))
    
    Button(interactive, text='Commence Regular War', command=self.query_execute_button_clicked).grid(row=3, column=0)
    
    # Results
    Label(interactive, text='Results:').grid(row=4, column=0)
    
    self.results = Text(interactive, height=8)
    self.results.grid(row=5, column=0)
    
    relf = create_frame(interactive, 4)
    relf.grid(row=6, column=0)
    
    Label(relf, text='Relevance Feedback Retrieval (used after Commence Regular War)').grid(row=1, column=0)

    relevant = create_frame(relf, 4)
    relevant.grid(row=2, column=0)
    Label(relevant,
          text='Relevant documents: (use the rank shown in the results).' +
               ' Ordered from most to least relevant. Comma separated.').grid(row=0,column=0)
    self.relevant_documents = StringVar()
    self.relevant_documents.set('For example: 7,1,6,3')
    Entry(relevant, width=75, textvariable=self.relevant_documents).grid(row=3, column=0)

    irrelevant = create_frame(relf, 4)
    irrelevant.grid(row=3, column=0)
    Label(irrelevant,
          text='Irrelevant documents: (use the rank shown in the results).' +
               ' Ordered from most to least irrelevant. Comma separated.').grid(row=0,column=0)
    self.irrelevant_documents = StringVar()
    self.irrelevant_documents.set('For example: 2,4')
    Entry(irrelevant, width=75, textvariable=self.irrelevant_documents).grid(row=3, column=0)
    
    method = create_frame(relf, 4)
    method.grid(row=4, column=0)
    self.method = StringVar()
    rb = Radiobutton(method, text='Rocchio', variable=self.method, value='rochio')
    rb.grid(row=1, column=0)
    rb.select()
    Radiobutton(method, text='Regular IDE', variable=self.method, value='ide_regular').grid(row=2, column=0)
    Radiobutton(method, text='IDE dec-hi', variable=self.method, value='ide_dec_hi').grid(row=3, column=0)
    
    options = create_frame(relf, 4)
    options.grid(row=5, column=0)
    Label(options, text='Please fill these (float) values if method is Rocchio').grid(row=0, column=0)
    Label(options, text='Beta:').grid(row=1, column=0)
    Label(options, text='Gamma:').grid(row=2, column=0)
    
    self.beta = StringVar()
    self.beta.set('1.0')
    self.gamma = StringVar()
    self.gamma.set('1.0')
    Entry(options, textvariable=self.beta).grid(row=1, column=1)
    Entry(options, textvariable=self.gamma).grid(row=2, column=1)
    
    Button(relf, text='Commence War with Relevance Feedback',
           command=self.relevance_feedback_button_clicked).grid(row=6, column=0)

  def save_retrieval_result_button_clicked(self):
    filename = tkFileDialog.asksaveasfilename()
    if filename:
      self.engine.SaveResultToFile(filename)

  def save_performance_button_clicked(self):
    filename = tkFileDialog.asksaveasfilename()
    if filename:
      self.engine.SavePerformanceToFile(filename)
  
  def _display_query(self, result):
    self.result = result

    # Undo everything
    self.results.delete(1.0, END)
    hyperlink = util.HyperlinkManager(self.results)
    
    def function_forwarder(func, parameter):
      param = parameter
      def ret_func():
        func(param)
      
      return ret_func

    def open_document(index):
      root = Tkinter.Toplevel()
      doc_view = DocumentViewer(root, self.result[index][1], self.result[index][0])

    self.rank_to_id = {}

    for i in range(len(self.result)):
      self.results.insert(INSERT, '%d: ' % (i+1))
      self.results.insert(INSERT, self.result[i][0], hyperlink.add(function_forwarder(open_document, i)))
      self.results.insert(INSERT, '\n')
      self.rank_to_id[i] = self.result[i][2]
  
  def query_execute_button_clicked(self):
    self._display_query(self.engine.ExecuteInteractiveQuery(self.query.get()))
  
  def relevance_feedback_button_clicked(self):
    # Generate Ids
    def CommaSeparatedRankToIds(input_txt):
      if input_txt == '':
        return []
      return [self.rank_to_id[x-1] for x in map(int, input_txt.split(','))]
    
    que = self.query.get()
    rel = CommaSeparatedRankToIds(self.relevant_documents.get())
    irrel = CommaSeparatedRankToIds(self.irrelevant_documents.get())
    method = self.method.get()
    if method == 'rochio':
      res = self.engine.ExecuteInteractiveQueryWithRelevanceFeedback(
        que, rel, irrel, method, beta=float(self.beta.get()), gamma=float(self.gamma.get()))
    else:
      res = self.engine.ExecuteInteractiveQueryWithRelevanceFeedback(que, rel, irrel, method)
    self._display_query(res)

class DocumentViewer:
  def __init__(self, master, document_text, document_title):
    self.master = master
    self.master.title('Impulse Engine MK 1.7 -- %s' % document_title)
      
    base = create_frame(master, 0)
    txt = Text(base)
    txt.insert(INSERT, document_text)
    txt.grid(row=0, column=0)

if __name__ == '__main__':
  root = Tkinter.Tk()
  mg = SetParameterIndexingWindow(root)
  root.mainloop();
